﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace thinger.MTHHelper
{
    public class IniConfigHelper
    {
        #region 方法说明

        //WritePrivateProfileString方法说明：

        //功能：将信息写入ini文件

        //    返回值：long,如果为0则表示写入失败，反之成功。

        //参数1(section) :写入ini文件的某个小节名称（不区分大小写）。

        //参数2(key) :上面section下某个项的键名(不区分大小写)。

        //参数3(val) :上面key对应的value

        //参数4(filePath):ini的文件名，包括其路径(example: "c:/config.ini")。如果没有指定路径，仅有文件名，系统会自动在windows目录中查找是否有对应的ini文件，如果没有则会自动在当前应用程序运行的根目录下创建ini文件。



        //GetPrivateProfileString方法使用说明：

        //功能：从ini文件中读取相应信息

        //    返回值：返回所取信息字符串的字节长度

        //    参数1(section):某个小节名(不区分大小写)，如果为空，则将在retVal内装载这个ini文件的所有小节列表。

        //参数2(key) :欲获取信息的某个键名(不区分大小写)，如果为空，则将在retVal内装载指定小节下的所有键列表。

        //参数3(def) :当指定信息，未找到时，则返回def，可以为空。

        //参数4(retVal) :一个字串缓冲区，所要获取的字符串将被保存在其中，其缓冲区大小至少为size。

        //参数5(size) :retVal的缓冲区大小(最大字符数量)。

        //参数6(filePath) :指定的ini文件路径，如果没有路径，则在windows目录下查找，如果还是没有则在应用程序目录下查找，再没有，就只能返回def了。

        #endregion


        #region API函数说明

        //[DllImport("kernel32")]
        //private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        //[DllImport("kernel32",EntryPoint = "GetPrivateProfileString")]
        //private static extern long GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        [DllImport("kernel32", EntryPoint = "GetPrivateProfileString")]
        private static extern uint GetPrivateProfileStringA(string section, string key, string def, byte[] retVal,
            int size, string filePath);

        #endregion

        #region 读写INI文件相关

        [DllImport("kernel32.dll", EntryPoint = "WritePrivateProfileString", CharSet = CharSet.Ansi)]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileString", CharSet = CharSet.Ansi)]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal,
            int size, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileInt(string lpApplicationName, string lpKeyName, int nDefault,
            string lpFileName);


        [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileSectionNames", CharSet = CharSet.Ansi)]
        private static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, int nSize, string filePath);

        [DllImport("KERNEL32.DLL ", EntryPoint = "GetPrivateProfileSection", CharSet = CharSet.Ansi)]
        private static extern int GetPrivateProfileSection(string lpAppName, byte[] lpReturnedString, int nSize,
            string filePath);

        #endregion

        #region 读写操作（字符串）

        //定义一个路径
        public static string filePath = string.Empty;

        public static string ReadIniData(string Section, string Key, string NoText)
        {
            return ReadIniData(Section, Key, NoText, filePath);
        }

        /// <summary>
        /// 读取INI数据
        /// </summary>
        /// <param name="Section">节点名</param>
        /// <param name="Key">键名</param>
        /// <param name="NoText"></param>
        /// <param name="iniFilePath"></param>
        /// <returns></returns>
        public static string ReadIniData(string Section, string Key, string NoText, string iniFilePath)
        {
            if (File.Exists(iniFilePath))
            {
                StringBuilder temp = new StringBuilder(1024);
                GetPrivateProfileString(Section, Key, NoText, temp, 1024, iniFilePath);
                return temp.ToString();
            }
            else
            {
                return string.Empty;
            }
        }


        public static bool WriteIniData(string Section, string Key, string Value)
        {
            return WriteIniData(Section, Key, Value, filePath);
        }

        /// <summary>
        /// 向INI写入数据
        /// </summary>
        /// <param name="Section"></param>
        /// <param name="Key"></param>
        /// <param name="Value"></param>
        /// <param name="iniFilePath"></param>
        /// <returns></returns>
        public static bool WriteIniData(string Section, string Key, string Value, string iniFilePath)
        {
            if (!File.Exists(iniFilePath)) File.Create(iniFilePath).Close();

            StringBuilder temp = new StringBuilder(1024);
            long OpStation = WritePrivateProfileString(Section, Key, Value, iniFilePath);
            if (OpStation == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        #endregion

        #region 配置节信息

        /// <summary>
        /// 读取一个ini里面所有的节
        /// </summary>
        /// <param name="sections"></param>
        /// <param name="path"></param>
        /// <returns>-1:没有节信息，0:正常</returns>
        public static int GetAllSectionNames(out string[] sections, string path)
        {
            int MAX_BUFFER = 32767;
            IntPtr pReturnedString = Marshal.AllocCoTaskMem(MAX_BUFFER);
            int bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, path);
            if (bytesReturned == 0)
            {
                sections = null;
                return -1;
            }

            string local = Marshal.PtrToStringAnsi(pReturnedString, (int)bytesReturned).ToString();
            Marshal.FreeCoTaskMem(pReturnedString);
            //use of Substring below removes terminating null for split
            sections = local.Substring(0, local.Length - 1).Split('\0');
            return 0;
        }

        /// <summary>
        /// 返回指定配置文件下的节名称列表
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<string> GetAllSectionNames(string path)
        {
            List<string> sectionList = new List<string>();
            int MAX_BUFFER = 32767;
            IntPtr pReturnedString = Marshal.AllocCoTaskMem(MAX_BUFFER);
            int bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, path);
            if (bytesReturned != 0)
            {
                string local = Marshal.PtrToStringAnsi(pReturnedString, (int)bytesReturned).ToString();
                Marshal.FreeCoTaskMem(pReturnedString);
                sectionList.AddRange(local.Substring(0, local.Length - 1).Split('\0'));
            }

            return sectionList;
        }

        /// <summary>
        /// 获取所有的Sections
        /// </summary>
        /// <param name="iniFilePath"></param>
        /// <returns></returns>
        public static List<string> ReadSections(string iniFilePath)
        {
            List<string> sectionList = new List<string>();
            byte[] buf = new byte[65536];
            uint len = GetPrivateProfileStringA(null, null, null, buf, buf.Length, iniFilePath);
            int j = 0;
            for (int i = 0; i < len; i++)
            {
                if (buf[i] == 0)
                {
                    sectionList.Add(Encoding.Default.GetString(buf, j, i - j));
                    j = i + 1;
                }
            }

            return sectionList;
        }

        /// <summary>
        /// 获取指定Section下的所有Keys
        /// </summary>
        /// <param name="SectionName"></param>
        /// <param name="iniFilePath"></param>
        /// <returns></returns>
        public static List<string> ReadKeys(string SectionName, string iniFilePath)
        {
            List<string> sectionList = new List<string>();
            byte[] buf = new byte[65536];
            uint len = GetPrivateProfileStringA(null, null, null, buf, buf.Length, iniFilePath);
            int j = 0;
            for (int i = 0; i < len; i++)
            {
                if (buf[i] == 0)
                {
                    sectionList.Add(Encoding.Default.GetString(buf, j, i - j));
                    j = i + 1;
                }
            }

            return sectionList;
        }

        /// <summary>
        /// 得到某个节点下面所有的key和value组合
        /// </summary>
        /// <param name="section">指定的节名称</param>
        /// <param name="keys">Key数组</param>
        /// <param name="values">Value数组</param>
        /// <param name="path">INI文件路径</param>
        /// <returns></returns>
        public static int GetAllKeyValues(string section, out string[] keys, out string[] values, string path)
        {
            byte[] b = new byte[65535]; //配置节下的所有信息
            GetPrivateProfileSection(section, b, b.Length, path);
            string s = System.Text.Encoding.Default.GetString(b); //配置信息
            string[] tmp = s.Split((char)0); //Key\Value信息
            List<string> result = new List<string>();
            foreach (string r in tmp)
            {
                if (r != string.Empty)
                    result.Add(r);
            }

            keys = new string[result.Count];
            values = new string[result.Count];
            for (int i = 0; i < result.Count; i++)
            {
                string[] item = result[i].Split(new char[] { '=' }); //Key=Value格式的配置信息
                //Value字符串中含有=的处理，
                //一、Value加""，先对""处理
                //二、Key后续的都为Value
                if (item.Length > 2)
                {
                    keys[i] = item[0].Trim();
                    values[i] = result[i].Substring(keys[i].Length + 1);
                }

                if (item.Length == 2) //Key=Value
                {
                    keys[i] = item[0].Trim();
                    values[i] = item[1].Trim();
                }
                else if (item.Length == 1) //Key=
                {
                    keys[i] = item[0].Trim();
                    values[i] = "";
                }
                else if (item.Length == 0)
                {
                    keys[i] = "";
                    values[i] = "";
                }
            }

            return 0;
        }

        /// <summary>
        /// 得到某个节点下面所有的key
        /// </summary>
        /// <param name="section">指定的节名称</param>
        /// <param name="keys">Key数组</param>
        /// <param name="path">INI文件路径</param>
        /// <returns></returns>
        public static int GetAllKeys(string section, out string[] keys, string path)
        {
            byte[] b = new byte[65535];

            GetPrivateProfileSection(section, b, b.Length, path);
            string s = System.Text.Encoding.Default.GetString(b);
            string[] tmp = s.Split((char)0);
            ArrayList result = new ArrayList();
            foreach (string r in tmp)
            {
                if (r != string.Empty)
                    result.Add(r);
            }

            keys = new string[result.Count];
            for (int i = 0; i < result.Count; i++)
            {
                string[] item = result[i].ToString().Split(new char[] { '=' });
                if (item.Length == 2)
                {
                    keys[i] = item[0].Trim();
                }
                else if (item.Length == 1)
                {
                    keys[i] = item[0].Trim();
                }
                else if (item.Length == 0)
                {
                    keys[i] = "";
                }
            }

            return 0;
        }

        /// <summary>
        /// 获取指定节下的Key列表
        /// </summary>
        /// <param name="section">指定的节名称</param>
        /// <param name="path">配置文件名称</param>
        /// <returns>Key列表</returns>
        public static List<string> GetAllKeys(string section, string path)
        {
            List<string> keyList = new List<string>();
            byte[] b = new byte[65535];
            GetPrivateProfileSection(section, b, b.Length, path);
            string s = System.Text.Encoding.Default.GetString(b);
            string[] tmp = s.Split((char)0);
            List<string> result = new List<string>();
            foreach (string r in tmp)
            {
                if (r != string.Empty)
                    result.Add(r);
            }

            for (int i = 0; i < result.Count; i++)
            {
                string[] item = result[i].Split(new char[] { '=' });
                if (item.Length == 2 || item.Length == 1)
                {
                    keyList.Add(item[0].Trim());
                }
                else if (item.Length == 0)
                {
                    keyList.Add(string.Empty);
                }
            }

            return keyList;
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="section"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<string> GetAllValues(string section, string path)
        {
            List<string> keyList = new List<string>();
            byte[] b = new byte[65535];
            GetPrivateProfileSection(section, b, b.Length, path);
            string s = System.Text.Encoding.Default.GetString(b);
            string[] tmp = s.Split((char)0);
            List<string> result = new List<string>();
            foreach (string r in tmp)
            {
                if (r != string.Empty)
                    result.Add(r);
            }

            for (int i = 0; i < result.Count; i++)
            {
                string[] item = result[i].Split(new char[] { '=' });
                if (item.Length == 2 || item.Length == 1)
                {
                    keyList.Add(item[1].Trim());
                }
                else if (item.Length == 0)
                {
                    keyList.Add(string.Empty);
                }
            }

            return keyList;
        }

        #endregion

        #region 通过值查找键（一个节中的键唯一，可能存在多个键值相同，因此反查的结果可能为多个）

        /// <summary>
        /// 第一个键
        /// </summary>
        /// <param name="section"></param>
        /// <param name="path"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string GetFirstKeyByValue(string section, string path, string value)
        {
            foreach (string key in GetAllKeys(section, path))
            {
                if (ReadString(section, key, "", path) == value)
                {
                    return key;
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// 所有键
        /// </summary>
        /// <param name="section"></param>
        /// <param name="path"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static List<string> GetKeysByValue(string section, string path, string value)
        {
            List<string> keys = new List<string>();
            foreach (string key in GetAllKeys(section, path))
            {
                if (ReadString(section, key, "", path) == value)
                {
                    keys.Add(key);
                }
            }

            return keys;
        }

        #endregion


        #region 具体类型的读写

        #region string

        /// <summary>
        ///
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="defaultValue" />
        /// <param name="path"></param>
        /// <returns></returns>
        public static string ReadString(string sectionName, string keyName, string defaultValue, string path)
        {
            const int MAXSIZE = 255;
            StringBuilder temp = new StringBuilder(MAXSIZE);
            GetPrivateProfileString(sectionName, keyName, defaultValue, temp, 255, path);
            return temp.ToString();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="value"></param>
        /// <param name="path"></param>
        public static void WriteString(string sectionName, string keyName, string value, string path)
        {
            WritePrivateProfileString(sectionName, keyName, value, path);
        }

        #endregion

        #region Int

        /// <summary>
        ///
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="defaultValue"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static int ReadInteger(string sectionName, string keyName, int defaultValue, string path)
        {

            return GetPrivateProfileInt(sectionName, keyName, defaultValue, path);

        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="value"></param>
        /// <param name="path"></param>
        public static void WriteInteger(string sectionName, string keyName, int value, string path)
        {

            WritePrivateProfileString(sectionName, keyName, value.ToString(), path);

        }

        #endregion

        #region bool

        /// <summary>
        /// 读取布尔值
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="defaultValue"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool ReadBoolean(string sectionName, string keyName, bool defaultValue, string path)
        {

            int temp = defaultValue ? 1 : 0;

            int result = GetPrivateProfileInt(sectionName, keyName, temp, path);

            return (result == 0 ? false : true);

        }

        /// <summary>
        /// 写入布尔值
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="value"></param>
        /// <param name="path"></param>
        public static void WriteBoolean(string sectionName, string keyName, bool value, string path)
        {
            string temp = value ? "1 " : "0 ";
            WritePrivateProfileString(sectionName, keyName, temp, path);
        }

        #endregion

        #endregion

        #region 删除操作

        /// <summary>
        /// 删除指定项
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="keyName"></param>
        /// <param name="path"></param>
        public static void DeleteKey(string sectionName, string keyName, string path)
        {
            WritePrivateProfileString(sectionName, keyName, null, path);
        }

        /// <summary>
        /// 删除指定节下的所有项
        /// </summary>
        /// <param name="sectionName"></param>
        /// <param name="path"></param>
        public static void EraseSection(string sectionName, string path)
        {
            WritePrivateProfileString(sectionName, null, null, path);
        }

        #endregion

        #region 判断节、键是否存在

        /// <summary>
        /// 指定节知否存在
        /// </summary>
        /// <param name="section"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool ExistSection(string section, string fileName)
        {
            string[] sections = null;
            GetAllSectionNames(out sections, fileName);
            if (sections != null)
            {
                foreach (var s in sections)
                {
                    if (s == section)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 指定节下的键是否存在
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool ExistKey(string section, string key, string fileName)
        {
            string[] keys = null;
            GetAllKeys(section, out keys, fileName);
            if (keys != null)
            {
                foreach (var s in keys)
                {
                    if (s == key)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        #endregion

        #region 同一Section下添加多个Key\Value

        /// <summary>
        ///
        /// </summary>
        /// <param name="section"></param>
        /// <param name="keyList"></param>
        /// <param name="valueList"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public static bool AddSectionWithKeyValues(string section, List<string> keyList, List<string> valueList,
            string path)
        {
            bool bRst = true;
            //判断Section是否已经存在，如果存在，返回false
            //已经存在，则更新
            //if (GetAllSectionNames(path).Contains(section))
            //{
            // return false;
            //}
            //判断keyList中是否有相同的Key，如果有，返回false

            //添加配置信息
            for (int i = 0; i < keyList.Count; i++)
            {
                WriteString(section, keyList[i], valueList[i], path);
            }

            return bRst;
        }

        #endregion
    }
}
